#include "ina226.h"
#include "softI2C.h"
#include "main.h"
#define INA226_ADDR 0x40
#define MAX_CURRENT_AMP 6.0
#define RSHUNT 10 // 单位毫欧
#define REG_CONFIG 0x00
#define REG_SHUNT_VOLTAGE 0x01
#define REG_BUS_VOLTAGE 0x02
#define REG_POWER 0x03
#define REG_CURRENT 0x04
#define REG_CALIBRATION 0x05

#define REG_CONFIG_RESET 0x8000
#define REG_CONFIG_DEFAULT 0x4127

// 平均样本数
#define REG_CONFIG_NUM_OF_AVG_1 (0 << 9)
#define REG_CONFIG_NUM_OF_AVG_4 (1 << 9)
#define REG_CONFIG_NUM_OF_AVG_16 (2 << 9)
#define REG_CONFIG_NUM_OF_AVG_64 (3 << 9)
#define REG_CONFIG_NUM_OF_AVG_128 (4 << 9)
#define REG_CONFIG_NUM_OF_AVG_256 (5 << 9)
#define REG_CONFIG_NUM_OF_AVG_512 (6 << 9)
#define REG_CONFIG_NUM_OF_AVG_1024 (7 << 9)

// 总线电压转换时间
#define REG_CONFIG_VBUSCT_140US (0 << 6)
#define REG_CONFIG_VBUSCT_204US (1 << 6)
#define REG_CONFIG_VBUSCT_332US (2 << 6)
#define REG_CONFIG_VBUSCT_588US (3 << 6)
#define REG_CONFIG_VBUSCT_1P1MS (4 << 6)
#define REG_CONFIG_VBUSCT_2P116MS (5 << 6)
#define REG_CONFIG_VBUSCT_4P156MS (6 << 6)
#define REG_CONFIG_VBUSCT_8P244MS (7 << 6)

// 采样电阻转换时间
#define REG_CONFIG_VSHCT_140US (0 << 3)
#define REG_CONFIG_VSHCT_204US (1 << 3)
#define REG_CONFIG_VSHCT_332US (2 << 3)
#define REG_CONFIG_VSHCT_588US (3 << 3)
#define REG_CONFIG_VSHCT_1P1MS (4 << 3)
#define REG_CONFIG_VSHCT_2P116MS (5 << 3)
#define REG_CONFIG_VSHCT_4P156MS (6 << 3)
#define REG_CONFIG_VSHCT_8P244MS (7 << 3)

// 模式设置
#define REG_CONFIG_SHUTDOWN (0 << 0)                 // 关机
#define REG_CONFIG_SHUNT_VOLT_TRIGGER (1 << 0)       // 采样电阻电压单次触发
#define REG_CONFIG_BUS_VOLT_TRIGGER (2 << 0)         // 总线电压单次触发
#define REG_CONFIG_SHUNT_AND_BUS_TRIGGER (3 << 0)    // 采样电阻和总线电压一起，单次触发
#define REG_CONFIG_SHUTDOWN2 (4 << 0)                // 关机
#define REG_CONFIG_SHUNT_VOLT_CONTINUOUS (5 << 0)    // 采样电阻电压连续模式
#define REG_CONFIG_BUS_VOLT_CONTINUOUS (6 << 0)      // 总线电压连续模式
#define REG_CONFIG_SHUNT_AND_BUS_CONTINUOUS (7 << 0) // 采样电阻和总线电压一起，连续模式
// INA226 SDA:PA15
// INA226 SCL: PA12

static float currentLSB = 0.0;
static float voltageLSB = 0.0;
static float cal = 0.0;
static LL_GPIO_InitTypeDef GPIO_InitStruct;

void ina226SclIn(void)
{
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void ina226SclOut(void)
{
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_12;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void ina226SclHigh(void)
{
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_12);
}

void ina226SclLow(void)
{
    LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_12);
}

void ina226SdaIn(void)
{
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void ina226SdaOut(void)
{
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void ina226SdaHigh(void)
{
    LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_15);
}

void ina226SdaLow(void)
{
    LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_15);
}

unsigned char ina226SdaRead(void)
{
    return LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_15);
}

void ina226Delay(void)
{
    // do nothing
}

SoftI2cHandler ina226I2cHandler =
    {
        .isErr = 0,
        .delay = ina226Delay,
        .sclHigh = ina226SclHigh,
        .sclIn = ina226SclIn,
        .sclLow = ina226SclLow,
        .sclOut = ina226SclOut,
        .sdaHigh = ina226SdaHigh,
        .sdaIn = ina226SdaIn,
        .sdaLow = ina226SdaLow,
        .sdaOut = ina226SdaOut,
        .sdaRead = ina226SdaRead,
};
// 0 success -1 failed

INA226_ErrTable ina226Init(void)
{
    INA226_ErrTable err = E_INA226_SUCCESS;
    unsigned int readVal = 0;
    unsigned int conf = 0;
    // 初始化I2C
    softI2cInit(&ina226I2cHandler);

    // 初始化ina226基础设置
    // 尝试和INA226进行通讯，并判定通讯是否成功
    softI2cWriteWordToAddr(&ina226I2cHandler, INA226_ADDR, REG_CONFIG, REG_CONFIG_RESET);
    softI2cWriteWordToAddr(&ina226I2cHandler, INA226_ADDR, REG_CONFIG, REG_CONFIG_DEFAULT);
    readVal = softI2cReadWordFromAddr(&ina226I2cHandler, INA226_ADDR, REG_CONFIG);
    if (readVal != REG_CONFIG_DEFAULT || ina226I2cHandler.isErr)
    {
        err = E_INA226_HW_ERR;
    }
    // 进行配置参数设置
    conf = REG_CONFIG_NUM_OF_AVG_16 | REG_CONFIG_VBUSCT_2P116MS | REG_CONFIG_VSHCT_2P116MS | REG_CONFIG_SHUNT_AND_BUS_CONTINUOUS;
    currentLSB = MAX_CURRENT_AMP / 32768.0;
    voltageLSB = 0.00125;
    cal = (unsigned int)(0.00512 / (currentLSB * RSHUNT * 0.001));
    softI2cWriteWordToAddr(&ina226I2cHandler, INA226_ADDR, REG_CONFIG, REG_CONFIG_RESET);
    softI2cWriteWordToAddr(&ina226I2cHandler, INA226_ADDR, REG_CONFIG, conf);
    softI2cWriteWordToAddr(&ina226I2cHandler, INA226_ADDR, REG_CALIBRATION, cal);
    if (ina226I2cHandler.isErr)
    {
        err = E_INA226_CONFIG_ERR;
    }
    return err;
}

float ina226GetCurrent(void) // unit : mA
{

    float ret = 0.0;
    unsigned int current;

    current = softI2cReadWordFromAddr(&ina226I2cHandler, INA226_ADDR, REG_CURRENT);
    if (ina226I2cHandler.isErr)
    {
        ret = 0.0;
    }
    else
    {

        ret = currentLSB * current;

    }
    if(ret >= 11.99)
    {
        ret = 0.0;
    }
    return ret;
}

float ina226GetVoltage(void) // unit : mV
{
    float ret = 0.0;
    unsigned int volt;
    volt = softI2cReadWordFromAddr(&ina226I2cHandler, INA226_ADDR, REG_BUS_VOLTAGE);
    if (ina226I2cHandler.isErr)
    {
        ret = 0.0;
    }
    else
    {
        ret = voltageLSB * volt;
    }

    return ret;
}

float ina226GetPower(void)
{
    float ret = 0.0;
    unsigned int volt;
    volt = softI2cReadWordFromAddr(&ina226I2cHandler, INA226_ADDR, REG_POWER);
    if (ina226I2cHandler.isErr)
    {
        ret = 0.0;
    }
    else
    {
        ret = voltageLSB * volt;
    }

    return ret;
}
